/**
 * @file example_010.cpp
 * @author 逆流 (1171267147@qq.com)
 * @brief Lazy类实现原型
 * @version 0.1
 * @date 2025-07-15
 * 
 * @copyright Copyright (c) 2025
 * 
 */
#include <functional>
#include <iostream>
#include <memory>

#include "utility/optional.hpp"

using std::cout;

template <typename T>
struct Lazy {
    Lazy() = default;
    template <typename Func, typename... Args>
    Lazy(Func&& func, Args&&... args) {
        // func_ = [&func, &args...]{ return func(args...);}
        func_ = std::bind(func, std::forward<Args>(args)...);
    }

    T& Value() {
        if (!value_.IsInit()) {
            value_ = func_();
        }

        return *value_;
    }

    bool IsCreated() const { return value_.IsInit(); }

private:
    std::function<T()> func_;
    ::Optional<T>      value_;
};

template <typename Func, typename... Args>
Lazy<typename std::result_of<Func(Args...)>::type> MakeLazy(Func&& func, Args&&... args) {
    return Lazy<typename std::result_of<Func(Args...)>::type>(std::forward<Func>(func), std::forward<Args>(args)...);
}

struct BigObject {
    BigObject() { std::cout << "BigObject()" << std::endl; }
};

struct MyStruct {
    MyStruct() {
        obj_ = MakeLazy([]() {
            return std::make_shared<BigObject>();
        });
    }

    void Load() { obj_.Value(); }

    Lazy<std::shared_ptr<BigObject>> obj_;
};

int main() {
    MyStruct s;
    cout << "before Load" << '\n';
    s.Load();
    return 0;
}